package com.gitee.grower.core.ui

import com.germ.germplugin.api.KeyType
import com.germ.germplugin.api.dynamic.gui.GermGuiScreen
import com.germ.germplugin.api.dynamic.gui.GermGuiSlot
import com.germ.germplugin.api.event.gui.GermGuiSlotClickEvent
import com.germ.germplugin.api.event.gui.GermGuiSlotPreClickEvent
import com.gitee.grower.ItemGrower
import com.gitee.grower.ItemGrowerAPI
import com.gitee.grower.ItemGrowerAPI.countItem
import com.gitee.grower.ItemGrowerAPI.growLevel
import com.gitee.grower.ItemGrowerAPI.takeoutItem
import com.gitee.grower.ItemGrowerAPI.toCommonValue
import com.gitee.grower.api.event.PlayerItemModifyGrowEvents
import com.gitee.grower.api.event.PlayerItemModifyGrowEvents.*
import com.gitee.grower.core.kether.playKether
import com.gitee.grower.core.kether.toKetherDouble
import com.gitee.grower.core.kether.toKetherFunction
import com.gitee.grower.core.kether.toKetherInt
import com.gitee.grower.core.scheme.Item
import com.gitee.grower.core.scheme.Operation
import com.gitee.grower.core.scheme.Scheme
import com.gitee.grower.util.germ.GermButtonDSL
import com.gitee.grower.util.germ.GermSlotDSL
import com.gitee.grower.util.germ.createDSL
import com.gitee.grower.util.germ.createGUI
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import taboolib.common.platform.event.SubscribeEvent
import taboolib.common.platform.function.info
import taboolib.common.platform.function.submitAsync
import taboolib.common.platform.service.PlatformExecutor
import taboolib.common.util.random
import taboolib.common.util.replaceWithOrder
import taboolib.common5.Coerce
import taboolib.library.configuration.ConfigurationSection
import taboolib.module.configuration.Config
import taboolib.module.configuration.Configuration
import taboolib.module.nms.getName
import taboolib.platform.compat.depositBalance
import taboolib.platform.compat.getBalance
import taboolib.platform.util.buildItem
import taboolib.platform.util.giveItem
import taboolib.platform.util.isAir
import taboolib.platform.util.sendLang

class GermLogicUI(val viewer: Player, val item: ItemStack) {

    companion object {

        @Config("germ-ui.yml")
        lateinit var config: Configuration

        val germUIRoot: ConfigurationSection
            get() = config.getConfigurationSection("grower-ui")!!

        val waitTime: Double
            get() = germUIRoot.getDouble("wait-time")

        val submit: ConfigurationSection
            get() = germUIRoot.getConfigurationSection("submit")!!

        val mainSlot: ConfigurationSection
            get() = germUIRoot.getConfigurationSection("main-slot")!!

        val fortuneSlot: ConfigurationSection
            get() = germUIRoot.getConfigurationSection("fortune-slot")!!

        val perfectSlot: ConfigurationSection
            get() = germUIRoot.getConfigurationSection("perfect-slot")!!

        @SubscribeEvent
        fun e(e: GermGuiSlotPreClickEvent) {
            if (e.germGuiScreen.guiName == germUIRoot.name) {

                if ((e.germGuiSlot.indexName.startsWith("item_") || e.germGuiSlot.indexName == mainSlot.name)) {
                    e.isCancelled = true
                }
                if (e.germGuiSlot.identity.startsWith("germplugin_backpack")) {
                    if (Coerce.toInteger(e.germGuiSlot.identity.split("_")[2]) == e.player.inventory.heldItemSlot) {
                        e.isCancelled = true
                    }
                }

            }
        }

    }

    var task: PlatformExecutor.PlatformTask? = null

    fun open() {

        if (item.isAir()) return

        val scheme = ItemGrowerAPI.getScheme(viewer, item)

        if (scheme == null) {
            viewer.sendLang("item-un-grow-scheme", item.getName())
            return
        }

        val structure = ItemGrowerAPI.getStructure(viewer, item, scheme)
        if (structure == null) {
            viewer.sendLang("item-un-grow-structure", item.getName())
            return
        }

        createGUI(viewer) {
            it.infuse(germUIRoot)

            it.addKeyHandler(KeyType.KEY_SPACE) { _, screen ->
                handleSubmit(screen, scheme, structure)
            }

            it.parts += createDSL<GermSlotDSL>(fortuneSlot) {
                it.identity = "@Grower:Fortune"
            }
            it.parts += createDSL<GermSlotDSL>(perfectSlot) {
                it.identity = "@Grower:Perfect"
            }
            it.parts += createDSL<GermSlotDSL>(mainSlot) {
                it.item = this.item
                it.identity = "@Grower:Main"
            }

            it.parts += createItems(structure)

            it.parts += createDSL<GermButtonDSL>(submit) {
                it.onClick { screen ->
                    handleSubmit(screen, scheme, structure)
                }
            }
            it.closed = { player, screen ->
                task?.cancel()
                player.giveItem(screen.getFortuneItem())
                player.giveItem(screen.getPerfectItem())
            }
        }
    }

    fun checkStructure(structure: Scheme.Structure?): Boolean {
        if (structure == null) {
            viewer.sendLang("item-un-grow-structure", item.getName())

        }
        return structure != null
    }

    fun GermGuiScreen.checkFortuneItem(): Boolean {
        val inferFortune = Infer.InferFortune(getFortuneItem())
        if (inferFortune.isValid && !inferFortune.match) {
            viewer.sendLang("fortune-not-match", inferFortune.item?.getName() ?: "__null__")
            return false
        }
        return true
    }

    fun GermGuiScreen.checkPerfectItem(): Boolean {

        val inferPerfect = Infer.InferPerfect(getPerfectItem())
        if (inferPerfect.isValid && !inferPerfect.match) {
            viewer.sendLang("perfect-not-match", inferPerfect.item?.getName() ?: "__null__")
            return false
        }
        return true
    }

    fun checkGold(structure: Scheme.Structure): Boolean {

        // Vault 金币检索
        if (viewer.getBalance() < structure.gold) {
            viewer.sendLang("player-gold-lack", structure.gold - viewer.getBalance())
            return false
        }
        return true
    }

    fun checkItems(scheme: Scheme, structure: Scheme.Structure): Boolean {
        // 材料检索
        val matchItem = ItemGrowerAPI.checkMisMatchItem(viewer, item, scheme, structure)
        if (matchItem.isNotEmpty()) {
            matchItem.forEach { viewer.sendLang("item-not-match", it.name()) }
            return false
        }
        return true
    }

    fun toLocalDescription(map: Map<String, Double>, type: String): List<String> {
        val temp = if (type == "success") {
            ItemGrower.descriptionTempSuccess
        } else {
            ItemGrower.descriptionTempSuccess
        }
        return map.map { temp.replaceWithOrder(it.key, toCommonValue(it.value)) }
    }

    fun handleSubmit(screen: GermGuiScreen, scheme: Scheme, structure: Scheme.Structure?) {
        var structure = structure

        if (!checkStructure(structure) || !screen.checkFortuneItem() || !screen.checkPerfectItem() || !checkGold(
                structure!!
            ) || !checkItems(scheme, structure)
        ) return

        screen.sendDos(submit.getStringList("clickDos"))
        task?.cancel()
        task = submitAsync(delay = Coerce.toLong(waitTime * 20.0)) {

            info(structure)
            if (!checkStructure(structure)) return@submitAsync

            val inferFortune = Infer.InferFortune(screen.getFortuneItem())
            if (inferFortune.isValid && !inferFortune.match) {
                viewer.sendLang("fortune-not-match", inferFortune.item?.getName() ?: "__null__")
                return@submitAsync
            }
            val inferPerfect = Infer.InferPerfect(screen.getPerfectItem())
            if (inferPerfect.isValid && !inferPerfect.match) {
                viewer.sendLang("perfect-not-match", inferPerfect.item?.getName() ?: "__null__")
                return@submitAsync
            }

            // 经济检索
            if (!checkGold(structure!!)) return@submitAsync

            // 材料检索
            if (!checkItems(scheme, structure!!)) return@submitAsync


            val growPre = Pre(viewer, item, scheme, structure!!, toKetherDouble(viewer, structure!!.chance, item))

            if (!growPre.call()) return@submitAsync

            structure!!.takeoutItem(viewer, item)
            inferFortune.takeItem(1)
            inferPerfect.takeItem(1)
            screen.updateFortuneItem(inferFortune)
            screen.updatePerfectItem(inferPerfect)
            viewer.depositBalance(structure!!.gold)
            // 概率为结构本身概率 + 祈福魔咒概率

            val description = mutableListOf<String>()

            if (random(growPre.chance)) {

                if (Succeed(viewer, item, scheme, structure!!).call()) {
                    description += toLocalDescription(
                        ItemGrowerAPI.modifyItemGrow(
                            viewer,
                            item,
                            scheme,
                            structure!!,
                            Operation.INCREASE
                        ),
                        "success"
                    )
                    viewer.sendLang("item-grow-success", item.getName(), "+${item.growLevel()}")
                    playKether(viewer, structure!!.successAction, item)
                    GermChildUI(viewer, item, description, "success").openChild()
                }

            } else {

                // 检索失败事件
                if (Failed(viewer, item, scheme, structure!!).call()) {
                    viewer.sendLang("item-grow-fail", item.getName(), "+${item.growLevel() + 1}")
                    playKether(viewer, structure!!.failAction, item)

                    val degradedPre = DegradedPre(
                        viewer,
                        item,
                        scheme,
                        structure!!,
                        toKetherDouble(viewer, structure!!.degradedChance, item) - inferFortune.get(viewer, item)
                    )

                    // 该阶段开启了掉级 并且成功掉级
                    if (structure!!.isDegraded && degradedPre.call()) {
                        if (random(degradedPre.chance)) {
                            if (DegradedPost(viewer, item, scheme, structure!!).call()) {
                                description += toLocalDescription(
                                    ItemGrowerAPI.modifyItemGrow(
                                        viewer,
                                        item,
                                        scheme,
                                        structure!!,
                                        Operation.DECREASE
                                    ),
                                    "fail"
                                )
                                viewer.sendLang("item-grow-degraded", item.getName())
                                playKether(viewer, structure!!.degradedAction, item)
                            } else {
                                return@submitAsync
                            }
                        } else if (inferFortune.match) {
                            viewer.sendLang("item-grow-degrade-perfect0", item.getName(), inferFortune.item!!.getName())
                            playKether(viewer, structure!!.degradedPerfectAction, item)
                        }


                    }


                    val negativePre = NegativePre(
                        viewer,
                        item,
                        scheme,
                        structure!!,
                        toKetherDouble(viewer, structure!!.negativeChance, item) - inferPerfect.get(viewer, item)
                    )

                    // 该阶段开启了负面buff 并且成功给予负面buff
                    // 负面buff计算公式 原生+保护魔咒
                    if (structure!!.isNegative && structure!!.negativeLore.isNotEmpty() && negativePre.call()) {
                        if (random(negativePre.chance)) {
                            val negativeString = toKetherFunction(viewer, structure!!.negativeLore.random(), item)
                            if (NegativePost(
                                    viewer,
                                    item,
                                    scheme,
                                    structure!!,
                                    negativeString
                                ).call()
                            ) {
                                description += negativeString
                                ItemGrowerAPI.modifyNegativeItem(viewer, item, scheme, structure!!, negativeString)
                                viewer.sendLang("item-grow-negative", item.getName(), negativeString)
                                playKether(viewer, structure!!.negativeAction, item)
                            }
                        } else if (inferPerfect.match) {
                            viewer.sendLang(
                                "item-grow-negative-perfect0",
                                item.getName(),
                                inferPerfect.item!!.getName()
                            )
                            playKether(viewer, structure!!.negativePerfectAction, item)
                        }
                    }
                    GermChildUI(viewer, item, description, "fail").openChild()
                }

            }
            Post(viewer, item, scheme, structure!!).call()
            screen.updateMainItem()
            // 刷新structure和ui内的材料列表
            structure = ItemGrowerAPI.getStructure(viewer, item, scheme)
            screen.clearItems()
            if (structure == null) {
                screen.clearItems()
            } else {
                screen.updateItems(structure!!)
            }
        }
    }

    fun GermGuiScreen.updateItems(structure: Scheme.Structure) {
        this.getGuiParts(GermGuiSlot::class.java).forEach {
            if (it.indexName.startsWith("item_")) {
                val index = Coerce.toInteger(it.indexName.split("_")[1])
                val itemIcon = structure.items.getOrNull(index)
                if (itemIcon == null) {
                    it.itemStack = null
                } else {
                    it.itemStack = createItem(itemIcon)
                }
            }
        }
    }

    fun createItems(structure: Scheme.Structure): List<GermSlotDSL> {
        val listOf = mutableListOf<GermSlotDSL>()
        germUIRoot.getKeys(false).forEach {
            if (it.startsWith("item_")) {
                val index = Coerce.toInteger(it.split("_")[1])
                val itemIcon = structure.items.getOrNull(index)

                listOf += createDSL<GermSlotDSL>(germUIRoot.getConfigurationSection(it)!!) {
                    it.identity = "@Grower:Item_$index"
                    if (itemIcon != null) {
                        it.item = createItem(itemIcon)
                    }
                }
            }
        }
        return listOf
    }

    fun createItem(itemIcon: Item): ItemStack {
        return buildItem(itemIcon.buildIcon(viewer)) {
            val toKetherInt = toKetherInt(viewer, itemIcon.amountScript, this@GermLogicUI.item)
            this.name += ItemGrower.appendAmount?.replaceWithOrder(itemIcon.countItem(viewer), toKetherInt) ?: ""
            this.amount = toKetherInt
        }
    }

    fun GermGuiScreen.clearItems() {
        this.getGuiParts(GermGuiSlot::class.java).forEach {
            if (it.indexName.startsWith("item_")) {
                it.itemStack = null
            }
        }
    }

    fun Item.name(): String {
        return if (this is Item.Default) {
            this.id
        } else {
            (this as Item.Condition).name
        }
    }


    fun GermGuiScreen.updateMainItem() {
        this.getGuiPart(mainSlot.name, GermGuiSlot::class.java)?.itemStack = item
    }

    fun GermGuiScreen.updateFortuneItem(infer: Infer) {
        this.getGuiPart(fortuneSlot.name, GermGuiSlot::class.java)?.itemStack = infer.item
    }

    fun GermGuiScreen.updatePerfectItem(infer: Infer) {
        this.getGuiPart(perfectSlot.name, GermGuiSlot::class.java)?.itemStack = infer.item
    }

    fun GermGuiScreen.getFortuneItem(): ItemStack? {
        return this.getGuiPart(fortuneSlot.name, GermGuiSlot::class.java).itemStack
    }

    fun GermGuiScreen.getPerfectItem(): ItemStack? {
        return this.getGuiPart(perfectSlot.name, GermGuiSlot::class.java).itemStack
    }

}